#include "ui/ui_task_list.h"
#include "utils/io_utils.h"
#include "utils/unit_utils.h"
#include "utils/ui_utils.h"
#include "model/request_api.h"
#include "ui/ui_download_task.h"
#include "utils/time_utils.h"

#include <stdlib.h>

static TaskListContext *context;

static DownloadTask *GetSelectedTask() {
  GtkTreeModel *task_store;
  GtkTreeIter iterator;
  if(gtk_tree_selection_get_selected(context->task_selection, &task_store, &iterator)) {
    /*双向链表→*/GList *selected_rows = gtk_tree_selection_get_selected_rows(context->task_selection, &task_store);

    int selected_index = gtk_tree_path_get_indices(/*因为可能是多选（我们这里ui配置了只能单选）,故是个list→*/g_list_first(selected_rows)->data)[0]/*←拿到的是个indices, 因为拿到的是一个tree(一个节点下还有子节点,子节点下还有子节点)*/;

    g_list_free_full(selected_rows, (GDestroyNotify) gtk_tree_path_free);

    PRINT_INT(selected_index);

    return g_slist_nth(context->download_task_list, selected_index)->data;
  }
  return NULL;
}

static void OnTaskListActivated(GtkTreeView *tree_view,
                                GtkTreePath *path,
                                GtkTreeViewColumn *column,
                                gpointer user_data) {
  DownloadTask *selected_download_task = GetSelectedTask();
  if (selected_download_task->task_info.status != STATUS_COMPLETED) {
    if(selected_download_task->task_info.status == STATUS_DOWNLOADING) {
      PauseSelectedTask();
    } else {
      ResumeSelectedTask();
    }
  }
}

static void CancelDownloadingAndDestroyTask(DownloadTask *download_task) {
  if (download_task->request_handler != NULL && download_task->task_info.status == STATUS_DOWNLOADING) {
    download_task->task_info.status = STATUS_REMOVING; //取消是需要一点时间的, 将is_running置为null后, 需要等到libcurl调用progress的回调时 才会真正取消, 故这里先做一个标记, 等下真正取消后要准备干掉内存时会走下面的分支
    CancelRequest(download_task->request_handler/*RequestContext*/);
  } else {
    DestroyDownloadTask(download_task);
  }
}

void InitTaskList(GtkBuilder *builder) {
  if (!context) {
    context = malloc(sizeof(TaskListContext));
    context->window = (GtkWindow *) gtk_builder_get_object(builder, "window");
    g_signal_connect_swapped(context->window, "destroy", G_CALLBACK(DestroyTaskList), NULL);

    context->task_store = (GtkListStore *) gtk_builder_get_object(builder, "task_store");
    context->task_selection = (GtkTreeSelection *) gtk_builder_get_object(builder, "task_selection");

    GtkTreeView *task_list_view = (GtkTreeView *) gtk_builder_get_object(builder, "task_tree");
    //双击之后 如果该任务还没有下载完成 会从暂停切换到下载 从下载切换到暂停
    g_signal_connect(G_OBJECT(task_list_view), "row-activated", G_CALLBACK(OnTaskListActivated), NULL);

    GPtrArray *task_infos = ListTaskInfos();

    context->download_task_list = NULL; //这一步很关键 赋值为null以后 我们后面调用相应的函数的时候 它的函数里边发现它没有被初始化 它才会去给它分配内存, 如果你不赋值为null的话, 它以为已经有了内存, 它就会直接追加, 就会导致内存访问的错误
    context->downloading_task_size = 0; //现在还没有开始下载

    for (int i = 0; i < task_infos->len; ++i) {
      TaskInfo *task_info = g_ptr_array_index(task_infos, i);
      TaskInfoDump(task_info);
      //注意↓ g_slist_append 的第一个参数如果为null, 则它会认为还没有初始化会进行初始化, 否则会直接追加
      context->download_task_list = g_slist_append/*单链表*/(context->download_task_list, CreateDownloadTask(context, task_info));
    }

    g_ptr_array_free(task_infos, TRUE/*同时销毁里面元素的内存*/);
  }
}

//点击+好 并且正确请求回 head请求后 执行
void AddTaskToList(TaskInfo *task_info) {
  context->download_task_list = g_slist_append(context->download_task_list, CreateDownloadTask(context, task_info));
}

void DestroyTaskList() {
  if (context) {
    g_slist_free_full(context->download_task_list, /*在释放list之前还会执行以下函数→*/(GDestroyNotify) CancelDownloadingAndDestroyTask);

    while (context->downloading_task_size) { //ui_download_task.c UpdateDownloadTaskWithStatus 中进行的 --

      /** 这里之所以要有下面的gtk_main_iteration+gtk_events_pending
       *  而不直接while (context->downloading_task_size)+sleep完事
       *  是因为当前函数(DestroyTaskList) 本身就在ui线程的loop里调用
       *  此时要想在它被调用期间 还想要消费其它事件(上面g_slist_free_full产生的)
       *  就只能通过 gtk_main_iteration+gtk_events_pending 的方式了*/

      //https://developer.gnome.org/gtk3/stable/gtk3-General.html
      //=== gtk_events_pending ===
      //Checks if any events are pending.
      //This can be used to update the UI and invoke timeouts etc. while doing some time intensive computation.
      //
      //Returns
      //TRUE if any events are pending, FALSE otherwise

      while(gtk_events_pending()/*有了新的事件了*/){

        //=== gtk_main_iteration ===
        //Runs a single iteration of the mainloop.
        //If no events are waiting to be processed GTK+ will block until the next event is noticed.
        //If you don’t want to block look at gtk_main_iteration_do() or check if any events are pending with gtk_events_pending() first.
        //Returns
        //TRUE if gtk_main_quit() has been called for the innermost mainloop

        //gtk_main_iteration和gtk_events_pending 一起使用 相当于 实时刷新

        gtk_main_iteration();
      }
      PRINTLNF("wait for task to stop: %d", context->downloading_task_size);
      SleepMs(100);

    }

    free(context);
    context = NULL;

    gtk_main_quit();
  }
}

void ResumeSelectedTask() {
  DownloadTask *selected_download_task = GetSelectedTask();
  if(selected_download_task && selected_download_task->task_info.status < STATUS_DOWNLOADING) {
    DownloadFile(selected_download_task,
                 &selected_download_task->request_handler,
                 &selected_download_task->task_info,

                 //↓3个是在ui线程做的回调 gdk_threads_add_idle
                 (OnRequestSuccess) OnDownloadCompleted,
                 (OnRequestError) OnDownloadFailed,
                 (OnRequestCancellation) OnDownloadCancelled,

                 //↓而这个是在 ui_download_task.c OnProgressUpdated 内部再自己调 gdk_threads_add_idle
                 (OnRequestProgress) OnProgressUpdated);

    UpdateDownloadTaskWithStatus(selected_download_task, STATUS_DOWNLOADING);
  }
}

void PauseSelectedTask() {
  DownloadTask *selected_download_task = GetSelectedTask();
  if (selected_download_task && selected_download_task->task_info.status == STATUS_DOWNLOADING) {
    CancelRequest(selected_download_task->request_handler);
  }
}

void RemoveSelectedTask() {
  DownloadTask *selected_download_task = GetSelectedTask();
  if (selected_download_task) {
    if (ShowConfirmDialog(context->window, "Do you want to remove this task?")) {
      context->download_task_list = g_slist_remove(context->download_task_list, selected_download_task); //从ui中移除
      DeleteTaskInfo(&selected_download_task->task_info); //从数据库中移除
      CancelDownloadingAndDestroyTask(selected_download_task); //停止下载 并 销毁内存
    }
  }
}
